package component.security.encrypt;

import java.security.*;
import java.security.spec.*;
import javax.crypto.*;

/**
 * 密钥工厂；负责生成密钥和密钥对
 */

public class KeyUtil {
  public KeyUtil() {
  }

  // 对称密钥算法表
  public final static String DES = "DES";
  public final static String DESede = "DESede";
  public final static String TRI_DES = "TripleDES";
  public final static String AES = "AES";
  public final static String BLOWFISH = "Blowfish";

  // 公开密钥算法表
  public final static String RSA = "RSA";
  public final static String DSA = "DSA";
  public final static String DH = "DH";

  /**
   * 以指定参数生成公开加密算法的密钥对
   * @param algorithm 公开密钥算法
   * @param seed 随机数种子
   * @param keysize 算法位长
   * @return 公开加密算法的密钥对
   * @throws NoSuchAlgorithmException 指定了不被支持的加密算法
   */
  public static KeyPair generateKeyPair(String algorithm, String seed,
                                        int keysize) throws
      NoSuchAlgorithmException {
    // 生成一个KeyPairGenerator实例
    KeyPairGenerator keygen = KeyPairGenerator.getInstance(algorithm,new org.bouncycastle.jce.provider.BouncyCastleProvider());
    // 伪随机数产生器PRNG(pseudo-random number generator )
    SecureRandom secrand = null;
    // 初始化随机数产生器
    if (seed != null) {
      secrand = new SecureRandom();
      secrand.setSeed(seed.getBytes());
    }
    // 初始化密钥生成器
    if (secrand != null) {
      keygen.initialize(keysize, secrand);
    }
    else {
      keygen.initialize(keysize);
      // 生成密钥公钥pubkey和私钥prikey
    }
    KeyPair keys = keygen.genKeyPair(); //生成密钥组
    return keys;
  }

  /**
   * 以指定参数生成公开加密算法的密钥对
   * @param algorithm 公开密钥算法
   * @param seed 随机数种子
   * @param param 加密算法参数对象
   * @return 公开加密算法的密钥对
   * @throws NoSuchAlgorithmException 指定了不被支持的加密算法
   * @throws InvalidAlgorithmParameterException 指定了错误的加密算法参数对象
   */
  public static KeyPair generateKeyPair(String algorithm, String seed,
                                        AlgorithmParameterSpec param) throws
      NoSuchAlgorithmException, InvalidAlgorithmParameterException {
    // 生成一个KeyPairGenerator实例
    KeyPairGenerator keygen = KeyPairGenerator.getInstance(algorithm);
    // 伪随机数产生器PRNG(pseudo-random number generator )
    SecureRandom secrand = null;
    // 初始化随机数产生器
    if (seed != null) {
      secrand = new SecureRandom();
      secrand.setSeed(seed.getBytes());
    }
    // 初始化密钥生成器
    if (secrand != null) {
      keygen.initialize(param, secrand);
    }
    else {
      keygen.initialize(param);
      // 生成密钥公钥pubkey和私钥prikey
    }
    KeyPair keys = keygen.generateKeyPair(); //生成密钥组
    return keys;
  }

  /**
   * 生成对称算法密钥
   * @param algorithm 对称加密算法名称
   * @param seed 随机数种子,用以产生随机数
   * @param keysize 指定的密钥长度
   * @return 对称加密算法的密钥
   * @throws NoSuchAlgorithmException 指定的加密算法有误
   */
  public static SecretKey generateKey(String algorithm, String seed,
                                      int keysize) throws
      NoSuchAlgorithmException {
    // 生成一个KeyGenerator实例
    KeyGenerator keygen = KeyGenerator.getInstance(algorithm);
    // 伪随机数产生器PRNG(pseudo-random number generator )
    SecureRandom secrand = null;
    // 初始化随机数产生器
    if (seed != null) {
      secrand = new SecureRandom();
      secrand.setSeed(seed.getBytes());
    }
    // 初始化密钥生成器
    if (secrand != null) {
      keygen.init(keysize, secrand);
    }
    else {
      keygen.init(keysize);
      // 生成密钥
    }
    SecretKey skey = keygen.generateKey();
    return skey;
  }

  /**
   * 通过密钥交换协议生成对称加密算法密钥
   * @param myprikey A方的私有密钥
   * @param yourpubkey B方的公开密钥
   * @param agreement 密钥交换协议名称
   * @param keyalg 对称加密算法名称
   * @return 对称加密算法密钥
   * @throws NoSuchAlgorithmException 指定的加密算法有误
   * @throws InvalidKeyException 指定的密钥信息有误
   */
  public static SecretKey generateSecretKeyWithAgreement(PrivateKey myprikey,
      PublicKey yourpubkey, String agreement, String keyalg) throws
      NoSuchAlgorithmException, InvalidKeyException {
    // 根据对方的公钥生成本地的对称密钥
    KeyAgreement keyAgree = KeyAgreement.getInstance(agreement != null ?
        agreement : myprikey.getAlgorithm());
    keyAgree.init(myprikey);
    keyAgree.doPhase(yourpubkey, true);
    SecretKey key = keyAgree.generateSecret(keyalg);
    return key;
  }

}